import os, sys
# import tushare as ts
import pandas as pd

import numpy as np
import talib


# KDJ指标
def KDJIndex(result, N, M1, M2):

    """这是KDJ指标，入参：最高价、最低价、收盘价
    RSV=（今日收盘价一最近9天的最低价）÷（最近9天的最高价一最近9天的最低价）×100
    当日K值=（2/3×前一日K值）+（1/3×当日RSV值）
　　 当日D值=（2/3×前一日D值）+（1/3×当日K值）
    J指标的计算公式为：J=（3×当日K值）一（2×当日D值）
　　 若无前一日K值与D值,则可分别用50来代替。
     1.指标>80 时，回档机率大；指标<20时，反弹机率大； 2.K在20左右向上交叉D时，视为买进信号；
     3.K在80左右向下交叉D时，    视为卖出信号； 4.J>100 时，股价易反转下跌；J<0 时，股价易反转上涨；
     5.KDJ 波动于50左右的任何信号，其作用不大。"""
    # result = result.astype('float')
    result['slowk'], result['slowd'] = talib.STOCH(
        result['high'].values,
        result['low'].values,
        result['close'].values,
        fastk_period=N,
        slowk_period=M1,
        slowk_matype=0,
        slowd_period=M2,
        slowd_matype=0)
    # 求出J值，J = (3*K)-(2*D)
    result['slowj'] = list(map(lambda x, y: 3 * x - 2 * y, result['slowk'], result['slowd']))

    return result['slowk'], result['slowd'], result['slowj']

# WR 指标
def WR(result, timeperiod=120):
    """ 当W&R高于85，即处于超卖状态，行情即将见底，应当考虑买进。当W&R低于15，即处于超买状态，行情即将见顶，
        应当考虑卖出。在W&R进入高位后，一般要回头，如果股价继续上升就产生了背离，是卖出信号。
        在W&R进入低位后，一般要反弹，如果股价继续下降就产生了背离。W&R连续几次撞顶（底），局部形成双重或多重顶（底），
        是卖出（买进）的信号。"""
    result['wr'] = talib.WILLR(result['high'], result['low'], result['close'], timeperiod)
    return result['wr']


# MACD指标
def MACD(result, fastperiod=12, slowperiod=26, signalperiod=9, fastmatype=1,slowmatype=1, signalmatype=1):
    '''
    参数设置:
        fastperiod = 12
        slowperiod = 26
        signalperiod = 9
    第一个macd值，对应于DIF，第二个值macd_signal，对应于dea，第三个值macd_hist对应于macd。
    DIF-DEA均为正，买入信号参考。
    DIF-DEA均为负，卖出信号参考。
    '''
    macddiff, macddea, macd = talib.MACDEXT(result['close'], fastperiod, fastmatype, slowperiod,
                                            slowmatype, signalperiod, signalmatype)
    macd = macd * 2

    return macddiff, macddea, macd

# ARBR人气意愿指标
def BRAR(result, timeperiod):
    """人气指标（AR）和意愿指标（BR）AR 和 BR 都是对通过对历史股价走势的分析，反映市场当前情况下多空双方的力量强弱对比，推断市场交易情绪，
    从而对趋势的形成与反转作出预判。AR刻画的是市场交易人气，人气越旺，股价越高，而股价攀升带来的赚钱效应又会不断带动人气上升，但是物极必反。
    当AR值升高至一定限度时，代表能量已经消耗殆尽，缺乏推升力道的股价，出现反转概率增大。
    BR反映的是市场交易意愿，以“反市场心理”为基础，当市场人气狂热时卖出，人气悲观时买进。
    双方的分界线是 100，100 以上是多方优势，100 以下是空方优势。
    买入信号：
    BR通常运行在AR上方，一旦BR跌破AR并在AR之下运行时，表明市场开始筑底，视为买进信号；BR<40,AR<60: 空方力量较强，但随时可能反转上涨，考虑买进。
    卖出信号：
    BR>400,AR>180，多方力量极强，但随时可能反转下跌，考虑卖出；BR快速上升，AR并未上升而是小幅下降或横盘，视为卖出信号
     如中信证券对五类市场指标进行主成分分析来构建投资者情绪，具体包括：(1)市场整体类指标：整体市盈率、市净率、换手率；
     (2)市场结构类指标：上涨家数比下跌家数、小盘股相对大盘股的超额收益率等；(3)IPO系列指标：股票首发上市家数、新股上市首日涨幅；
     (4)封闭式基金折价率；(5)资金流动指标：A股账户净增加数。
     股票市场上，随着多空双方的较量，股价会向上或向下偏离这一平衡价位区，股价偏离得越大，说明力量越大，偏离得越小，说明力量越小。
     因此。利用股票各种价格之间的关系，找到这个平衡价位区，对研判多空力量的变化起着重要的作用。
     而ARBR指标就是根据股票的开盘价、收盘价、最高价和最低价之间的关系来分析多空力量的对比，预测股价的未来走势。
     ARBR指标计算简单，容易理解，但是使用起来并非容易，需要深厚的实盘交易经验才能作出准确判断。
     另外，ARBR指标也存在一定的局限性，如只利用了历史价格信息，而忽略了成交量的重要性。"""
    #result = result.astype('float')
    result = result[-60:]
    result['HO'] = result.high - result.open
    result['OL'] = result['open'] - result['low']
    result['HCY'] = result['high'] - result['close'].shift(1)
    result['CYL'] = result['close'].shift(1) - result['low']
    #计算AR、BR指标
    result['AR']=talib.SUM(result['HO'], timeperiod)/talib.SUM(result['OL'], timeperiod)*100
    result['BR']=talib.SUM(result['HCY'], timeperiod)/talib.SUM(result['CYL'], timeperiod)*100
    return result['AR'].dropna(), result['BR'].dropna()

# CYR市场相对强弱指标
def CYR(result, period=13, m = 5):
    """
    CYR是成本均线派生出的指标,是13日成本均线的升降幅度;
    把持股成本抬高的速度作为衡量一只股票走势强弱的标志，市场成本抬高的越快走势越强，反之走势越弱。
    CYR指标值在0.25～0.75之间的股票近期上涨的概率相对较大，做股票时尽量买该范围内的。
    :param result:
    :param period:
    :return:
    """
    result = result.astype('float')
    # 调用talib计算指数移动平均线的值
    result['EMA13'] = talib.EMA(np.array(result['amount']), timeperiod=period)
    result['EMA5'] = talib.EMA(np.array(result['volume']), timeperiod=m)
    dive = 0.01 * result['EMA13']/result['EMA5']
    tempDive = dive[1:]
    lastDive = dive[:-1]
    # tempDive = dive[-1:]
    # lastDive = dive[-2:-1]
    result['CYR'] = (tempDive /lastDive - 1) * 100

    return result['CYR']


def AMO(result):
    """
    成交量信号，成交金额越大，代表越热门：
    底部起涨点出现大成交金额，代表攻击量；
    头部地区出现大成交金额，代表出货量
    :param result:
    :return:
    """

def LB(result, LB_N):
    """
    量比是指股市开市后平均每分钟的成交量与过去N个交易日平均每分钟成交量之比 （N=5）
    当天开盘截至到当前时刻（check_date），平均每分钟的成交手数，除以过去N天平均每分钟的成交手数，
    这里的unit就是分钟级别的，所以不用unit属性；
    GG=成交量(手)/昨日成交量(手)的N日累和
    ZS=大盘成交量/昨日大盘成交量的N日累和
    DBLB=GG/ZS
    MADBLB=DBLB的M日简单移动平均

    量比指股市开市后平均每分钟的成交量与过去N个交易日平均每分钟成交量之比、
    量比0.5成交量萎缩到极致，变盘随时发生。 量比0.8--1.5成交量处于正常水平。量比1.5--2.5温和放量，将会延续原有趋势。
    量比2.5--5明显放量，可以采取相应行动了。量比5--10放巨量表现，趋势已到末期。量比>10极端放量，趋势已经到默契，可以考虑反向操作。
    :param result:
    :return:
    """
    # 前timeperiod平均交易量
    # result['LB'] = talib.EMA(np.array(result['amount'].shift(1)), timeperiod=MACD_M2)
    # result['LB'] = result['amount']/talib.SUM(result['amount'].shift(1), LB_N)

    result['LB'] = result['amount'] / talib.MA(np.array(result['amount'].shift(1)), timeperiod=LB_N)
    return result['LB']

def VRSI(result):
    """
    VRSI>20 为超买；VRSI<20 为超卖；
    VRSI 以50为中界线，大于50视为多头行情，小于50视ta为空头行情；
    VRSI 在80以上形成Ｍ头或头肩顶形态时，视为向下反转信号；
    VRSI 在20以下形成Ｗ底或头肩底形态时，视为向上反转信号；
    VRSI 向上突破其高点连线时，买进；VRSI 向下跌破其低点连线时，卖出。
    :param result:
    :return:
    """

def BBANDS(result, BOLL_M, matype=talib.MA_Type.EMA):
    """
    为BBI与BOLL的迭加；
    高价区收盘价跌破BBI线，卖出信号；
    低价区收盘价突破BBI线，买入信号；
    BBI线向上，股价在BBI线之上，多头势强；
    BBI线向下，股价在BBI线之下，空头势强。
    MA_Type: 0=SMA, 1=EMA, 2=WMA, 3=DEMA, 4=TEMA, 5=TRIMA, 6=KAMA, 7=MAMA, 8=T3 (Default=SMA)
    :param result:
    :return:
    """
    upper, middle, lower = talib.BBANDS(result['close'], BOLL_M ,matype)
    return upper, middle, lower


def MA(result, timeperiod):
    """
    1.股价高于平均线，视为强势；股价低于平均线，视为弱势 2.平均线向上涨升，具有助涨力道；平均线向下跌降，具有助跌力道；
    3.二条以上平均线向上交叉时，买进； 4.二条以上平均线向下交叉时，卖出； 5.移动平均线的信号经常落后股价，若以EXPMA 、VMA 辅助，可以改善。
    :param result:
    :return:
    """
    result['MA'] = talib.MA(result['close'], timeperiod = timeperiod, matype = 0)
    return result['MA']


def OBV(result):
    realObv = talib.OBV(result['close'], result['volume'])
    return realObv

def Amount(result, OBV_TimePeriod):
    amount = talib.EMA(np.array(result['amount']), timeperiod=OBV_TimePeriod)
    return amount


def MFI(result, MFI_TimePeriod):
    """
    资金流量指标
    :param result:
    :return:
    """
    mfi = talib.MFI(result['high'], result['low'], result['close'], result['volume'], MFI_TimePeriod)
    return mfi